package com.gxa.service.impl;

import com.gxa.exception.CustomerException;
import com.gxa.mapper.UserMapper;
import com.gxa.pojo.dto.LoginDto;
import com.gxa.pojo.dto.TokenDto;
import com.gxa.pojo.entity.User;
import com.gxa.service.UserService;
import com.gxa.utils.MessageCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author lch
 * @date 2024/3/25 16:06
 * @description
 **/
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    //用户登录短信前缀
    public final static  String USER_LOGIN_SMS="user_login_sms:";

    public static final String LOGIN_TOKEN="login_token:";

    public static final String REFRESH_TOKEN="refresh_token:";

    //token过期时间2小时
    public static final Integer LOGIN_EXPIRE=60*60*2;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 一键登录
     * @param loginDto
     * @return
     */
    @Override
    public TokenDto loginByPhone(LoginDto loginDto) {

        //判断手机号是否正确
        if(!loginDto.getPhone().matches("^1[3-9]\\d{9}$")){
            log.error("手机号格式错误");
            throw new CustomerException(MessageCode.PHONE_ERROR);
        }

        //获取redis存储的登录验证码
        String code = (String) redisTemplate.boundValueOps(USER_LOGIN_SMS + loginDto.getPhone()).get();

        //判断验证码是否过期
        if(StringUtils.isEmpty(code)){
            log.error("验证码已经过期");
            throw  new CustomerException(MessageCode.CODE_EXPIRE);
        }

        //判断验证码是否正确
        if (!code.equals(loginDto.getCode())) {
            log.error("验证码输入错误");
            throw  new CustomerException(MessageCode.CODE_ERROR);
        }

        //根据手机号码查询用户信息
        User user= this.userMapper.findUserByPhone(loginDto.getPhone());

        //判断改用户是否已经注册
        if(user==null){
            //注册新用户
            log.info("注册新用户{}",loginDto.getPhone());
            user=new User();
            user.setUserTel(loginDto.getPhone());
            user.setUserNick("用户:"+loginDto.getPhone());
            user.setUserBirth(new Date());
            this.userMapper.insertUser(user);
        }

        TokenDto tokenDto=new TokenDto();

        //处理重复登录
        if (user.getToken()!=null) {
            //当前用户已经登录
            log.info("当前用户{}已经登录，正在删除token:{}",user.getUserTel(), user.getToken());
            //删除redis中登录用户的token
            redisTemplate.delete(LOGIN_TOKEN + user.getToken());
        }

        //生成新的token
        String token = UUID.randomUUID().toString().replace("-", "");

        user.setToken(token);

        //保存用户信息到redis
        redisTemplate.boundValueOps(LOGIN_TOKEN + token).set(user);

        //设置token失效时间
        redisTemplate.boundValueOps(LOGIN_TOKEN + token).expire(LOGIN_EXPIRE, TimeUnit.SECONDS);

        //生成刷新token
        String refreshToken = UUID.randomUUID().toString().replace("-", "");

        //设置刷新token
        user.setRefreshToken(refreshToken);

        //设置失效时间2个月
        Calendar endTime = Calendar.getInstance();
        endTime.add(Calendar.DAY_OF_MONTH, 60);
        user.setRefreshTokenExpire(endTime.getTime());

        tokenDto.setToken(token);
        tokenDto.setRefreshToken(refreshToken);

        this.userMapper.updateUser(user);
        log.info("用户{}成功登录，登录的token为:{}", user.getUserTel(),token);

        return tokenDto;
    }


    /**
     * 根据token查询用户信息
     * @param token
     * @return
     */
    @Override
    public User findUserByToken(String token) {

        //判断token是否为空
        if (token==null) {
            log.info("token为空");
            throw new CustomerException(MessageCode.TOKEN_NOT_EMPTY);
        }

        //根据token在redis查询用户信息
        User user = (User) redisTemplate.boundValueOps(LOGIN_TOKEN+ token).get();
        if (user == null) {
            log.error("找不到改用户，无效token");
            throw new CustomerException(MessageCode.TOKEN_ERROR);
        }

        //token续期2小时
        redisTemplate.boundValueOps(LOGIN_TOKEN + token).expire(LOGIN_EXPIRE, TimeUnit.SECONDS);

        return user;
    }


    /**
     * 根据刷新token获取最新的token
     * @param refreshToken
     * @return
     */
    @Override
    public String loginByRefreshToken(String refreshToken) {
        //根据刷新token查找用户信息
        User user = this.userMapper.findUserByRefreshToken(REFRESH_TOKEN + refreshToken);

        if (user == null) {
            log.error("无效token");
            throw new CustomerException(MessageCode.TOKEN_ERROR);
        }

        //判断刷新token是否过期
        if (new Date().getTime() > user.getRefreshTokenExpire().getTime()) {
            log.error("刷新token失效，用户需要重新登录");
            throw new CustomerException(MessageCode.TOKEN_ERROR);
        }

        //处理重复登录
        if (user.getToken()!=null) {
            //当前用户已经登录
            log.info("当前用户{}已经登录，正在删除token:{}",user.getUserTel(), user.getToken());
            //删除redis中登录用户的token
            redisTemplate.delete(LOGIN_TOKEN + user.getToken());
        }

        //4.生成token
        String token = UUID.randomUUID().toString().replace("-", "");

        //5.存储用户信息到redis
        redisTemplate.boundValueOps(LOGIN_TOKEN + token).set(user);

        log.info("登录的token为:{}", token);

        //6.设置失效时间
        redisTemplate.boundValueOps(LOGIN_TOKEN + token).expire(LOGIN_EXPIRE, TimeUnit.SECONDS);


        //更新token
        user.setToken(token);
        this.userMapper.updateUser(user);

        return token;
    }
}
